using System;
using System.Text;
using BSDS.Core.Data.Local;
using BSDS.Core.Infrastructure.Logging;
using BSDS.Core.Model.Services;
using BSDS.Core.Model.Services.Jobs;
using BSDS.Core.Model.Services.Jobs.Core;
using BSDS.Core.Model.Services.Uploading;
using BSDS.Core.Model.Conversion;
using BSDS.Core.Model.Conversion.Processing;

namespace BSDS.Commands.Commands.Implementation
{
    public class UploadCommand : CommandBase
    {
        private readonly UploadService uploadService;
        private readonly AccountService accountService;
        private readonly DataRepository dataRepository;
        private readonly JobRepository jobRepository;
        private readonly JobService jobService;
        private readonly Logger logger;
        private readonly UploadCommandConfiguration config;

        private readonly DateTime startTime;
        private string publishDate;

        public override string Description { get { return CreateDescription(); }}

        public UploadCommand(UploadService uploadService, AccountService accountService, DataRepository dataRepository, 
            JobRepository jobRepository, JobService jobService, Logger logger, UploadCommandConfiguration config)
        {
            this.uploadService = uploadService;
            this.accountService = accountService;
            this.dataRepository = dataRepository;
            this.jobRepository = jobRepository;
            this.jobService = jobService;
            this.logger = logger;
            this.config = config;

            startTime = DateTime.Now;
        }

        public override CommandResult Execute(ExecutionContext context)
        {
            if (!string.IsNullOrEmpty(config.DropFilenamePrefix) && !config.InputFilename.StartsWith(config.DropFilenamePrefix))
            {
                string message = "Filename must start with \"" + config.DropFilenamePrefix + "\" : " + config.InputFilename;
                logger.Log("File Ingored. " + message);

                return CommandResult.Error("Unsupported file was dropped", message);
            }

            var data = dataRepository.LoadFromFile(config.InputFilename, config.ConvertMode);
            
            data.ZeroOutEmptyLatitudeLongitudeEntities();

            if (config.OutputDataFormat != DataFormat.OriginalFormat && data.OriginalFormat == DataFormat.Xml)
            {
                throw new ArgumentException("/toPipe and /toTab are not allowed for XML files.");
            }

            // Merge columns if required
            if (config.MergeConfigurationFile != string.Empty)
            {
                //MergeColumnsProcessor.CreateSampleData();
                MergeColumnsProcessor.LoadConfiguration(config.MergeConfigurationFile);
                MergeColumnsProcessor.MergeColumns(data);
            }

            // Delete columns if required
            if (config.DeleteConfigurationFile != string.Empty)
            {
                //DeleteColumnsProcessor.CreateSampleData();
                DeleteColumnsProcessor.LoadConfiguration(config.DeleteConfigurationFile);
                DeleteColumnsProcessor.DeleteColumns(data);
            }

            // Insert columns if required
            if (config.InsertConfigurationFile != string.Empty)
            {
                //InsertColumnsProcessor.CreateSampleData();
                InsertColumnsProcessor.LoadConfiguration(config.InsertConfigurationFile);
                InsertColumnsProcessor.InsertColumns(data);
            }

            var outputFormat = config.OutputDataFormat == DataFormat.OriginalFormat ? data.OriginalFormat : config.OutputDataFormat; 
            
            var job = uploadService.ScheduleUpload(data, config.DataSourceName, outputFormat, config.EntityTypeName, config.QueryKey);

            job.Command = context.CommandInfo.ToString();
            jobRepository.Save(job);

            var state = jobService.WaitForEnd(job.Id, uploadService);

            logger.Log("Upload job finished " + state.EndResult.ComplitionStatus);
            
            if (state.EndResult.ComplitionStatus != JobComplitionStatus.Success)
            {
                return CommandResult.Error("Upload error", state.EndResult.ComplitionStatus.ToString());
            }

            if (accountService.DataSourceExists(job.DataSourceName))
            {
                publishDate = accountService.GetDataSourceInformation(job.DataSourceName).LastUpdate;
            }

            return CommandResult.Success();
        }

        private string CreateDescription()
        {
            var builder = new StringBuilder();

            builder.Append("UPLOAD START TIME: " + startTime.ToLongTimeString()).Append(Environment.NewLine)
                   .Append("DATA SOURCE NAME: " + config.DataSourceName).Append(Environment.NewLine)
                   .Append("LAST PUBLISH DATE:  " + publishDate);

            return builder.ToString();
        }
    }

    public class UploadCommandConfiguration
    {
        public string InputFilename { get; private set; }
        public string DataSourceName { get; private set; }
        public DataFormat OutputDataFormat { get; private set; }
        public FormatConvertMode ConvertMode { get; private set; }
        public string EntityTypeName { get; private set; }
        public string QueryKey { get; private set; }
        public string DropFilenamePrefix { get; private set; }
        public string MergeConfigurationFile { get; private set; }
        public string DeleteConfigurationFile { get; private set; }
        public string InsertConfigurationFile { get; private set; }

        public UploadCommandConfiguration(string inputFilename, string dataSourceName, DataFormat outputDataFormat, FormatConvertMode convertMode, 
            string entityTypeName, string queryKey, string dropFilenamePrefix, string mergeConfigurationFile, string deleteConfigurationFile, 
            string insertConfigurationFile)
        {
            InputFilename = inputFilename;
            DataSourceName = dataSourceName;
            OutputDataFormat = outputDataFormat;
            ConvertMode = convertMode;
            EntityTypeName = entityTypeName;
            QueryKey = queryKey;
            DropFilenamePrefix = dropFilenamePrefix;
            MergeConfigurationFile = mergeConfigurationFile;
            DeleteConfigurationFile = deleteConfigurationFile;
            InsertConfigurationFile = insertConfigurationFile;
        }
    }
}